#ifndef _m4aformat_h_
#define _m4aformat_h_

#include <stdint.h>
#include <stddef.h>
#include <assert.h>
/*
Audio object type:
    0: Null
    1: AAC Main
    2: AAC LC (Low Complexity)
    3: AAC SSR (Scalable Sample Rate)
    4: AAC LTP (Long Term Prediction)
    5: SBR (Spectral Band Replication)
    6: AAC Scalable
    7: TwinVQ
    8: CELP (Code Excited Linear Prediction)
    9: HXVC (Harmonic Vector eXcitation Coding)
    10: Reserved
    11: Reserved
    12: TTSI (Text-To-Speech Interface)
    13: Main Synthesis
    14: Wavetable Synthesis
    15: General MIDI
    16: Algorithmic Synthesis and Audio Effects
    17: ER (Error Resilient) AAC LC
    18: Reserved
    19: ER AAC LTP
    20: ER AAC Scalable
    21: ER TwinVQ
    22: ER BSAC (Bit-Sliced Arithmetic Coding)
    23: ER AAC LD (Low Delay)
    24: ER CELP
    25: ER HVXC
    26: ER HILN (Harmonic and Individual Lines plus Noise)
    27: ER Parametric
    28: SSC (SinuSoidal Coding)
    29: PS (Parametric Stereo)
    30: MPEG Surround
    31: (Escape value)
    32: Layer-1
    33: Layer-2
    34: Layer-3
    35: DST (Direct Stream Transfer)
    36: ALS (Audio Lossless)
    37: SLS (Scalable LosslesS)
    38: SLS non-core
    39: ER AAC ELD (Enhanced Low Delay)
    40: SMR (Symbolic Music Representation) Simple
    41: SMR Main
    42: USAC (Unified Speech and Audio Coding) (no SBR)
    43: SAOC (Spatial Audio Object Coding)
    44: LD MPEG Surround
    45: USAC


audio config:
    0: Defined in AOT Specifc Config
    1: 1 channel: front-center
    2: 2 channels: front-left, front-right
    3: 3 channels: front-center, front-left, front-right
    4: 4 channels: front-center, front-left, front-right, back-center
    5: 5 channels: front-center, front-left, front-right, back-left, back-right
    6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
    7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
    8-15: Reserved
*/
/*
 @ eg:
 @ hex : FF F14C 402A A1A8
 @ bin : 1111 1111 1111  0  00 1 0100 1100 0100 0000 0010 1010 1010 0001 1010
*/
struct mpeg4_aac_t
{
    uint32_t syncword;
    uint8_t id;
    uint16_t layer;
    uint8_t protection_absent;
	uint8_t profile;  //  2 - AAC LC 常用
	uint8_t sampling_frequency_index; // 8K - 96K
    uint8_t private_bit;
	uint8_t channel_configuration;
    uint8_t originality_copy;
    uint8_t home;
    uint8_t copyrighted_identifi_bit;
    uint8_t copyrighted_identifi_start;
	uint32_t extension_frequency; // 播放频率(AAC-HE v1/v2 sbr/ps)
	uint32_t sampling_frequency;  // 解码频率, 只是用于解码
	uint8_t channels; // 只是用于解码
	int sbr; // sbr flag, 只是用于解码-----解决低码流下提供全带宽的编码而不会产生产生多余的信号
	int ps; // ps flag, 只是用于解码 ----- 从立体声音轨里提取出能够表征立体声信息的一系列参数；然后使用一个单声道音轨来表征原立体声音轨；
	uint8_t pce[64];
	int  npce; // pce bytes
};

struct mpeg4_bits_t
{
	uint8_t* data;
	size_t size;
	size_t bits; // offset bit
	int error;
};

// 45 种主声道
enum mpeg4_aac_object_type
{
	MPEG4_AAC_MAIN = 1,
	MPEG4_AAC_LC,
	MPEG4_AAC_SSR,
	MPEG4_AAC_LTP,
	MPEG4_AAC_SBR,      
	MPEG4_AAC_SCALABLE,
	MPEG4_AAC_TWINVQ,
	MPEG4_AAC_CELP,
	MPEG4_AAC_HVXC,
	MPEG4_AAC_TTSI = 12,
	MPEG4_AAC_MAIN_SYNTHETIC,
	MPEG4_AAC_WAVETABLE_SYNTHETIC,
	MPEG4_AAC_GENERAL_MIDI,
	MPEG4_AAC_ALGORITHMIC_SYNTHESIS, 
	MPEG4_AAC_ER_LC, 
	MPEG4_AAC_ER_LTP = 19,
	MPEG4_AAC_ER_SCALABLE,
	MPEG4_AAC_ER_TWINVQ, 
	MPEG4_AAC_ER_BSAC, 
	MPEG4_AAC_ER_AAC_LD,
	MPEG4_AAC_ER_CELP,
	MPEG4_AAC_ER_HVXC,
	MPEG4_AAC_ER_HILN,
	MPEG4_AAC_ER_PARAMTRIC,
	MPEG4_AAC_SSC,
	MPEG4_AAC_PS, 
	MPEG4_AAC_MPEG_SURROUND, 
	MPEG4_AAC_LAYER_1 = 32, 
	MPEG4_AAC_LAYER_2, 
	MPEG4_AAC_LAYER_3, 
	MPEG4_AAC_DST,
	MPEG4_AAC_ALS, 
	MPEG4_AAC_SLS, 
	MPEG4_AAC_SLS_NON_CORE, 
	MPEG4_AAC_ER_AAC_ELD, 
	MPEG4_AAC_SMR_SIMPLE, 
	MPEG4_AAC_SMR_MAIN, 
	MPEG4_AAC_USAC_NO_SBR, 
	MPEG4_AAC_SAOC, 
	MPEG4_AAC_LD_MEPG_SURROUND, 
	MPEG4_AAC_USAC, 
};

enum mpeg4_audio_profile
{
	MPEG4_AAC_PROFILE, // AAC LC
	MPEG4_HIGH_EFFICIENCY_AAC_PROFILE, // AAC LC, SBR (<=128 kbps)
	MPEG4_HE_AAC_V2_PROFILE, // AAC LC, SBR, PS ( 16 - 48 kbit/s)
	MPEG4_MAIN_AUDIO_PROFILE, // AAC Main, AAC LC, AAC SSR, AAC LTP, AAC Scalable, TwinVQ, CELP, HVXC, TTSI, Main synthesis
	MPEG4_SCALABLE_AUDIO_PROFILE, // AAC LC, AAC LTP, AAC Scalable, TwinVQ, CELP, HVXC, TTSI
	MPEG4_SPEECH_AUDIO_PROFILE, // CELP, HVXC, TTSI
	MPEG4_SYNTHETIC_AUDIO_PRIFILE, // TTSI, Main synthesis
	MPEG4_HIGH_QUALITY_AUDIO_PROFILE, // AAC LC, AAC LTP, AAC Scalable, CELP, ER AAC LC, ER AAC LTP, ER AAC Scalable, ER CELP
	MPEG4_LOW_DELAY_AUDIO_PROFILE, // CELP, HVXC, TTSI, ER AAC LD, ER CELP, ER HVXC
	MPEG4_NATURAL_AUDIO_PRIFILE, // AAC Main, AAC LC, AAC SSR, AAC LTP, AAC Scalable, TwinVQ, CELP, HVXC, TTSI, ER AAC LC, ER AAC LTP, ER AAC Scalable, ER TwinVQ, ER BSAC, ER AAC LD, ER CELP, ER HVXC, ER HILN, ER Parametric
	MPEG4_MOBILE_AUDIO_INTERNETWORKING_PROFILE, // ER AAC LC, ER AAC Scalable, ER TwinVQ, ER BSAC, ER AAC LD
	MPEG4_HD_AAC_PROFILE, // AAC LC, SLS
	MPEG4_ALS_SIMPLE_PROFILE, // ALS
};
enum mpeg4_aac_frequency
{
	MPEG4_AAC_96000 = 0,
	MPEG4_AAC_88200,	// 0x1
	MPEG4_AAC_64000,	// 0x2
	MPEG4_AAC_48000,	// 0x3
	MPEG4_AAC_44100,	// 0x4
	MPEG4_AAC_32000,	// 0x5
	MPEG4_AAC_24000,	// 0x6
	MPEG4_AAC_22050,	// 0x7
	MPEG4_AAC_16000,	// 0x8
	MPEG4_AAC_12000,	// 0x9
	MPEG4_AAC_11025,	// 0xa
	MPEG4_AAC_8000,		// 0xb
	MPEG4_AAC_7350,		// 0xc ---  还有2个保留 和最后一个指定频率   共三个
};

#define mpeg4_bits_read_uint8(bits, n)		(uint8_t)mpeg4_bits_read_n(bits, n)
#define mpeg4_bits_read_uint16(bits, n)		(uint16_t)mpeg4_bits_read_n(bits, n)
#define mpeg4_bits_read_uint32(bits, n)		(uint32_t)mpeg4_bits_read_n(bits, n)
#define mpeg4_bits_read_uint64(bits, n)		(uint64_t)mpeg4_bits_read_n(bits, n)
#define mpeg4_bits_write_uint8(bits, v, n)	mpeg4_bits_write_n(bits, (uint64_t)v, n)
#define mpeg4_bits_write_uint16(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
#define mpeg4_bits_write_uint32(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)
#define mpeg4_bits_write_uint64(bits, v, n) mpeg4_bits_write_n(bits, (uint64_t)v, n)

static inline void mpeg4_bits_init(struct mpeg4_bits_t* bits, void* data, size_t size)
{
	bits->data = (uint8_t*)data;
	bits->size = size;
	bits->bits = 0;
	bits->error = 0;
}

static inline int mpeg4_bits_error(struct mpeg4_bits_t* bits)
{
	return bits->error;
}

static inline void mpeg4_bits_aligment(struct mpeg4_bits_t* bits, int n)
{
	bits->bits = (bits->bits + n - 1) / n * n;
}

static inline size_t mpeg4_bits_remain(struct mpeg4_bits_t* bits)
{
	return bits->error ? 0 : (bits->size * 8 - bits->bits);
}

static inline void mpeg4_bits_skip(struct mpeg4_bits_t* bits, size_t n)
{
	bits->bits += n;
}

static inline int mpeg4_bits_read(struct mpeg4_bits_t* bits)
{
	uint8_t bit;
	assert(bits && bits->data && bits->size > 0);
	if (bits->bits >= bits->size * 8)
	{
		bits->error = -1;
		return 0; // throw exception
	}

	bit = bits->data[bits->bits/8] & (0x80U >> (bits->bits%8));
	bits->bits += 1; // update offset
	return bit ? 1 : 0;
}

static inline uint64_t mpeg4_bits_read_n(struct mpeg4_bits_t* bits, int n)
{
	int m;
	size_t i;
	uint64_t v;

	assert(n > 0 && n <= 64);
	assert(bits && bits->data && bits->size > 0);
	if (bits->bits + n > bits->size * 8 || n > 64 || n < 0)
	{
		bits->error = -1;
		return 0; // throw exception
	}

	m = n;
	v = bits->data[bits->bits / 8] & (0xFFU >> (bits->bits%8)); // remain valid value
	if (n <= 8 - (int)(bits->bits % 8))
	{
		v = v >> (8 - (bits->bits % 8) - n); // shift right value
		bits->bits += n;
		return v;
	}

	n -= 8 - (int)(bits->bits % 8);
	for (i = 1; n >= 8; i++)
	{
		assert(bits->bits / 8 + i < bits->size);
		v <<= 8;
		v += bits->data[bits->bits / 8 + i];
		n -= 8;
	}

	if (n > 0)
	{
		v <<= n;
		v += bits->data[bits->bits / 8 + i] >> (8 - n);
	}

	bits->bits += m;
	return v;
}
static inline uint64_t mpeg4_bits_read_uvlc(struct mpeg4_bits_t* bits)
{
	uint64_t value;
	int leadingZeros;
	for (leadingZeros = 0; !mpeg4_bits_read(bits); ++leadingZeros)
	{
	}

	if (leadingZeros >= 32)
		return (1ULL << 32) - 1;
	
	value = mpeg4_bits_read_n(bits, leadingZeros);
	return (1ULL << leadingZeros) - 1 + value;
}

static inline uint64_t mpeg4_bits_read_latm(struct mpeg4_bits_t* bits)
{
	int len;
	len = (int)mpeg4_bits_read_n(bits, 2);
	return mpeg4_bits_read_n(bits, (len + 1) * 8);
}

static inline int mpeg4_bits_write(struct mpeg4_bits_t* bits, int v)
{
	assert(bits && bits->data && bits->size > 0);
	if (bits->bits >= bits->size * 8)
	{
		bits->error = -1;
		return -1; // throw exception
	}

	if(v)
		bits->data[bits->bits / 8] |= (0x80U >> (bits->bits % 8));
	bits->bits += 1; // update offset
	return 0;
}

static inline int mpeg4_bits_write_n(struct mpeg4_bits_t* bits, uint64_t v, int n)
{
	int m;
	size_t i;

	assert(n > 0 && n <= 64);
	assert(bits && bits->data && bits->size > 0);
	if (bits->bits + n > bits->size * 8 || n > 64 || n < 0)
	{
		bits->error = -1;
		return -1; // throw exception
	}

	m = n;
	v = v << (64 - n); // left shift to first bit

	bits->data[bits->bits / 8] |= v >> (56 + (bits->bits % 8)); // remain valid value
	v <<= 8 - (bits->bits % 8);
	n -= 8 - (int)(bits->bits % 8);

	for (i = 1; n > 0; i++)
	{
		assert(bits->bits / 8 + i < bits->size);
		bits->data[bits->bits / 8 + i] = (uint8_t)(v >> 56);
		v <<= 8;
		n -= 8;
	}
	bits->bits += m;
	return 0;
}



int mpeg4_aac_adts_save(const struct mpeg4_aac_t* aac, size_t payload, uint8_t* data, size_t bytes);
int mpeg4_aac_adts_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);

int mpeg4_aac_audio_specific_config_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
int mpeg4_aac_audio_specific_config_save(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes);

int mpeg4_aac_stream_mux_config_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
int mpeg4_aac_stream_mux_config_save(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes);

int mpeg4_aac_profile_level(const struct mpeg4_aac_t* aac);


int mpeg4_aac_audio_frequency_to(enum mpeg4_aac_frequency index);
int mpeg4_aac_audio_frequency_from(int frequence);


uint8_t mpeg4_aac_channel_count(uint8_t channel_configuration);

int mpeg4_aac_adts_frame_length(const uint8_t* data, size_t bytes);




int mpeg4_aac_audio_specific_config_load2(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
int mpeg4_aac_audio_specific_config_save2(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes);
int mpeg4_aac_adts_pce_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);
int mpeg4_aac_adts_pce_save(uint8_t* data, size_t bytes, const struct mpeg4_aac_t* aac);
int mpeg4_aac_stream_mux_config_load2(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac);






#endif



